在Javascript中,除了几种原始类型外,其余皆为对象(Object,Array ...),既然对象如此重要,那就列举一下在Javascript中如何创建对象:

通过Object构造函数创建对象实例
var person = new Object();
person.name = 'krew';
person.age = 26;
对象字面量

对象字面量是对象定义的一种简写形式,目的在于简化创建包含大量属性的对象的过程。

var person = {
  name : 'krew',
  age : 26
}
工厂模式

工厂模式是一种设计模式,通过对创建具体对象的过程进行抽象。使用函数来封装创建对象的细节,可以无数次地调用用该函数,每次都可以得到包含制定内容的对象。

function personFactory(name, age){
  var obj = new Object();
  obj.name = name;
  obj.age = age;
  obj.sayName = function(){
    console.log(this.name);
  }
  return obj;
}

var person1 = personFactory('krew', 26);  
var person2 = personFactory('john', 20);
构造函数模式

基于工厂模式创建对象虽然方便,但是创建出来的对象没有特定的对象类型(比如原生对象Object, Array的实例都有自己的类型),所以就采用构造函数模式来创建对象,就能解决识别对象类型的问题。

function Person(name, age){
  this.name = name;
  this.age = age;
  this.sayName = function() {
    console.log(this.name);
  }
}

var person1 = new Person('krew', 26);
var person2 = new Person('john', 20);

person1.sayName();  // 'krew'
person2.sayName();  // 'john'

person1.constructor == Person  // true
person2.constructor == Person  // true
原型模式

每个函数在创建的时候,就会根据特定的规则为该函数创建一个prototype属性,这个属性是指向函数的原型对象的指针。这个原型对象的包含可以由特定类型的所有实例共享的属性和方法。所以,在构造函数的prototype属性上添加属性与方法,该构造函数的所有实例都会在原型链上查找到这些属性与方法。

function Person() {
}
Person.prototype.name = 'krew';
Person.prototype.age = 26;
Person.prototype.sayName = function() {
  console.log(this.name);
}

var person1 = new Person();
var person2 = new Person();

person1.sayName();  // 'krew'
person2.sayName();  // 'krew'
组合构造函数和原型模式

由于原型对象中的属性是被很多实例所共享的,对于引用类型的属性值,将会存在实例间无法隔离的问题:

function Person() {
}
Person.prototype = {
  constructor : Person,
  name : 'krew',
  age : 26,
  friends : ['john', 'kitty'],
  showFriends : function() {
    console.log(this.friends);
  }
}
var person1 = new Person();
var person2 = new Person();

person1.friends.push('petter');

person1.showFriends()  // ['john', 'kitty', 'petter']
person2.showFriends()  // ['john', 'kitty', 'petter']

可以看到,仅是在实例person1的friends属性上添加值,但person2也跟着变化。这是因为friends数组存在于Person.prototype而非person1中,person1与person2中的friends皆为引用Person.prototype中的friends,所以当通过person1来改变friends的时候,person2中的friends也会反映出来。
通过组合构造函数与原型模式可以解决上面出现的问题,构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性,每个实例会有自己的一份实例属性,同时又共享着方法的引用,极大的节省了内存。

function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.sayName = function() {
  console.log(this.name);
}

var person1 = new Person('krew', 26);
var person2 = new Person('john', 20);

person1.sayName();  // 'krew'
person2.sayName();  // 'john'
动态原型模式
function Person(name, age){
  this.name = name;
  this.age = age;
  if (typeof this.sayName != 'function') {
    Person.prototype.sayName = function() {
      console.log(this.name);
    }
  }
}

var person1 = new Person('krew', 26);
var person2 = new Person('john', 20);

person1.sayName();  // 'krew'
person2.sayName();  // 'john'
寄生构造函数模式
function Person(name, age) {
  var obj = new Object();
  obj.name = name;
  obj.age = age;
  obj.sayName = function() {
    console.log(this.name);
  }
  return obj;
}

var person1 = new Person('krew', 26);
var person2 = new Person('john', 20);

person1.sayName();  // 'krew'
person2.sayName();  // 'john'
稳妥构造函数模式
function Person(name) {
  var obj = new Object();
  obj.sayName = function() {
    console.log(name);
  }
  return obj;
}

var person1 = Person('krew');
var person2 = Person('john');

person1.sayName();  // 'krew'
person2.sayName();  // 'john'

krew
1.3k 声望25 粉丝

脚踏实地